﻿/**	allocator.h
 *	----	Create Time Stamp	--2005-09-27 21:38:17--
 *-----------------------------------------------------------------------------
 *	Mean	:简单的内存池
 *	Author	:Nick Shallery	(nicknide@gmail.com)
 *	Version	:1.0.32.64	(2009-09-21 01:05:30)
 *-----------------------------------------------------------------------------
**/	/*YOU HAVE ALL LEFT WITH THIS CODE WHILE YOU KEEP COMMENT IN EVERY COPY.*/


#ifndef     __cplusplus
#	error      Must Have C++ Complier Support
#endif  //  __cplusplus


#if			!defined(__LOLIX__TOY_ALLOCATOR__K_IN_G__)
#define		__LOLIX__TOY_ALLOCATOR__K_IN_G__

#if			!defined(__LOLIX__LOLI_X_CFG__K_IN_G__)
	#include	"../lolix_cfg.h"
#endif	//	!defined(__LOLIX__LOLI_X_CFG__K_IN_G__)

#if			!defined(__LOLIX__LOLIX_INSTANCE__K_IN_G__)
	#include	"../lolix_inst.h"
#endif	//	!defined(__LOLIX__LOLIX_INSTANCE__K_IN_G__)
#if			!defined(__LOLIX__LOLI_X_MACRO__K_IN_G__)
	#include	"../lolix_macro.h"
#endif	//	!defined(__LOLIX__LOLI_X_MACRO__K_IN_G__)
#if			!defined(__LOLIX__TOY__STD_V2T__NICK__K_IN_G__)
	#include	"./std_v2t.hpp"
#endif	//	!defined(__LOLIX__TOY__STD_V2T__NICK__K_IN_G__)


#include	<new>


#if			defined(new)
	#define		__LOLIX__TMP_DEF__NEED_POP_NEW_DEF	1
	#pragma	push_macro("new")
	#undef	new
#else	//	defined(new)
	#define		__LOLIX__TMP_DEF__NEED_POP_NEW_DEF	0
#endif	//	defined(new)



namespace lolix{
	namespace _help{
		typedef	void*	vt_ptr;	//	VS 有这样的BUG:
		//	void* __declspec(nothrow) __stdcall func(...);	LOST here;
		//	you must typedef this void* type, maybe it cann't make clean * during this declera

	}
	namespace toy{
		namespace _help{
			class	mem_trait;
		}
	}
}


#if			LOLIX_CFG__OPEN_MEM_ALLOC_TRACE
	#define		__LOLIX__TOY__ALLOCATE_STM__ALLOC_WITH_NAME__(pptr, size, name)		_alc->allocate((pptr), (size), (name))
	#define		__LOLIX__TOY__ALLOCATE_STM__DEALLOC_WITH_NAME__(ptr, size, name)	_alc->deallocate((ptr), (size), (name))
#else	//	LOLIX_CFG__OPEN_MEM_ALLOC_TRACE
	#define		__LOLIX__TOY__ALLOCATE_STM__ALLOC_WITH_NAME__(pptr, size, name)		_alc->allocate((pptr), size)
	#define		__LOLIX__TOY__ALLOCATE_STM__DEALLOC_WITH_NAME__(ptr, size, name)	_alc->deallocate((ptr), size)
#endif	//	LOLIX_CFG__OPEN_MEM_ALLOC_TRACE

#if			LOLIX_CFG__THROWS_EXCEPT && !defined(LOLIX_PRJ) && !defined(LXBIN_PRJ)
	#include	<stdexcept>
	#include	<cstdio>

	#define	__LOLIX__DO_AT_LESS_MEMORY__(size, name)	\
		do{char buf[64]; _snprintf(buf, 63\
		, "allocator %I" LOLIX_CFG__SIZE_TYPE_BITS_SIZE_STRING "u lost, the name is: %s"\
		, size, name); buf[63] = 0; throw std::bad_alloc(buf);}while(0)

#else	//	LOLIX_CFG__THROWS_EXCEPT && !defined(LOLIX_PRJ) && !defined(LXBIN_PRJ)
	#define	__LOLIX__DO_AT_LESS_MEMORY__(size, name)	return 0

#endif	//	LOLIX_CFG__THROWS_EXCEPT && !defined(LOLIX_PRJ) && !defined(LXBIN_PRJ)

#define		__LOLIX_ALLOC_CONSTRUCT(tp_name, _Ty)							\
	__LOLIX_ALLOC_DEFAULT_CONSTRUCT(tp_name, _Ty)							\
		LOLIX_INLINE_CALL													\
		tp_name<_Ty, mem_trait>(::lolix::dynamic_allocator* alloc)			\
			: _alc(alloc)													\
		{																	\
			_alc->inc_ref();												\
		}																	\
																			\
		LOLIX_INLINE_CALL	tp_name<_Ty, mem_trait>(const this_type& o)		\
			: _alc(o.get_allocator())										\
		{																	\
			_alc->inc_ref();												\
		}																	\
		template	<typename _OtherType>									\
		LOLIX_INLINE_CALL	tp_name<_Ty, mem_trait>(_OtherType* o)			\
			: _alc(o)														\
		{																	\
			_alc->inc_ref();												\
		}																	\
		template	<typename _OtherType>									\
		LOLIX_INLINE_CALL	tp_name<_Ty, mem_trait>(_OtherType& o)			\
			: _alc((lolix::dynamic_allocator*)o)							\
		{																	\
			_alc->inc_ref();												\
		}

#define	__LOLIX_ALLOC_DEFAULT_CONSTRUCT(tp_name, _Ty)

/////////////////////////////////////////////////////////////////////////////
#define		LOLIX_TRACE_ALLOC_TYPEDEF(sz_name, last_name)					\
	__LOLIX_TRACE_ALLOC_TYPEDEF__(sz_name, LOLIX_DEF__LINK_SYMBOL(last_name, __LINE__), last_name)

/////////////////////////////////////////////////////////////////////////////
#define		__LOLIX_TRACE_ALLOC_TYPEDEF__(sz_name, tp_name, last_name)		\
	LOLIX_ALLOC(sz_name, tp_name);											\
	typedef tp_name<void>	last_name

/////////////////////////////////////////////////////////////////////////////
#define		LOLIX_ALLOC(sz_name, tp_name)									\
	template<typename _Ty, typename _T_MEM_TRAIT = ::lolix::toy::_help::mem_trait>	\
	class tp_name;															\
	template<typename _Ty, typename _T_MEM_TRAIT>							\
	void swap(tp_name<_Ty, _T_MEM_TRAIT>& tl, tp_name<_Ty, _T_MEM_TRAIT>& tr)\
	{ tl.swap(tr); }														\
	template<typename _Ty>													\
	class tp_name<_Ty, ::lolix::toy::_help::mem_trait>						\
		: private ::lolix::toy::v2t_trait<_Ty>								\
	{																		\
		typedef	::lolix::toy::_help::mem_trait	mem_trait;					\
		typedef	tp_name<_Ty, mem_trait>			this_type;					\
		typedef ::lolix::toy::v2t_trait<_Ty>	base_type;					\
	public:																	\
		enum { THREAD_SAFE_TYPE = ::lolix::THREAD_SAFE_MRW };				\
		typedef typename base_type::const_pointer	const_pointer;			\
		typedef typename base_type::const_reference	const_reference;		\
		typedef typename base_type::difference_type	difference_type;		\
		typedef typename base_type::pointer			pointer;				\
		typedef typename base_type::reference		reference;				\
		typedef typename base_type::size_type		size_type;				\
		typedef typename base_type::value_type		value_type;				\
																			\
		template<typename _Other>											\
		struct rebind														\
		{																	\
			typedef tp_name<_Other, mem_trait> other;						\
		};																	\
																			\
		LOLIX_INLINE_CALL pointer address(reference _Val) const{return (&_Val);}		\
		LOLIX_INLINE_CALL const_pointer address(const_reference _Val) const	\
			{return (&_Val);}												\
																			\
		LOLIX_INLINE_CALL void deallocate(pointer _Ptr, size_type m_size)	\
		{																	\
			__LOLIX__TOY__ALLOCATE_STM__DEALLOC_WITH_NAME__					\
					(_Ptr, m_size*sizeof(*_Ptr), sz_name);					\
		}																	\
																			\
		LOLIX_INLINE_CALL pointer allocate(size_type cnt)					\
		{																	\
			void* ptr;														\
			const size_type a_size = cnt * sizeof(value_type);				\
			__LOLIX__TOY__ALLOCATE_STM__ALLOC_WITH_NAME__					\
					(&ptr, a_size, sz_name);								\
			if ( !ptr )														\
				__LOLIX__DO_AT_LESS_MEMORY__(a_size, sz_name);				\
			return static_cast<pointer>(ptr);								\
		}																	\
																			\
		LOLIX_INLINE_CALL pointer allocate(size_type _Count, const void*)	\
		{																	\
			return (allocate(_Count));										\
		}																	\
																			\
		LOLIX_INLINE_CALL void construct(pointer _Ptr)						\
		{																	\
			new(_Ptr)value_type;											\
		}																	\
																			\
		template<typename _To>												\
		LOLIX_INLINE_CALL void construct(pointer _Ptr, _To& _Val)			\
		{																	\
			new(_Ptr)value_type(_Val);										\
		}																	\
		template<typename _T0, typename _T1>								\
		LOLIX_INLINE_CALL void construct(pointer _Ptr, _T0& _V0, _T1& _V1)	\
		{																	\
			new(_Ptr)value_type(_V0, _V1);									\
		}																	\
		LOLIX_INLINE_CALL void construct(pointer _Ptr, const _Ty& _Val)		\
		{																	\
			new(_Ptr)value_type(_Val);										\
		}																	\
		LOLIX_INLINE_CALL void destroy(pointer _Ptr)						\
		{																	\
			(_Ptr = _Ptr);													\
			_Ptr->~_Ty();													\
		}																	\
																			\
		LOLIX_INLINE_CALL size_type max_size() const						\
		{																	\
			size_type _Count = (size_type)(-1) / sizeof (_Ty);				\
			return (0 < _Count ? _Count : 1);								\
		}																	\
																			\
		template<class _O>													\
		LOLIX_INLINE_CALL bool operator == (const tp_name<_O, mem_trait>& o)			\
		{ return this->_alc == o._alc; }									\
		template<class _O>													\
		LOLIX_INLINE_CALL bool operator != (const tp_name<_O, mem_trait>& o)			\
		{ return !(this_type::operator == (o)); }							\
																			\
		__LOLIX_ALLOC_CONSTRUCT(tp_name, _Ty);								\
		LOLIX_INLINE_CALL	~tp_name<_Ty, mem_trait>(void)					\
		{																	\
			_alc->release();												\
		}																	\
																			\
		LOLIX_INLINE_CALL	this_type& operator = ( const this_type& o)		\
		{																	\
			if ( o._alc != this->_alc )										\
			{																\
				this->_alc->release();										\
				_alc = o._alc;												\
				_alc->inc_ref();											\
			}																\
																			\
			return *this;													\
		}																	\
																			\
		template<typename _To>												\
		LOLIX_INLINE_CALL	void swap(tp_name<_To, mem_trait>& o)			\
		{																	\
			::lolix::dynamic_allocator* tmp = o._alc;						\
			o._alc = this->_alc;											\
			this->_alc = tmp;												\
		}																	\
																			\
		::lolix::dynamic_allocator* get_allocator(void)const				\
		{ return _alc; }													\
		operator ::lolix::dynamic_allocator* (void)const					\
		{ return _alc; }													\
	private:																\
		mutable ::lolix::dynamic_allocator*	_alc;							\
	};																		\
	template< >																\
	class tp_name<void, ::lolix::toy::_help::mem_trait>						\
	: private ::lolix::toy::v2t_trait<void>									\
	{																		\
		typedef	::lolix::toy::_help::mem_trait	mem_trait;					\
		typedef	tp_name<void, mem_trait>		this_type;					\
		typedef ::lolix::toy::v2t_trait<void>	base_type;					\
	public:																	\
		enum { THREAD_SAFE_TYPE = ::lolix::THREAD_SAFE_MRW };				\
		typedef base_type::const_pointer	const_pointer;					\
		typedef base_type::difference_type	difference_type;				\
		typedef base_type::pointer			pointer;						\
		typedef base_type::size_type		size_type;						\
		typedef base_type::value_type		value_type;						\
																			\
		template<typename _Other>											\
		struct rebind														\
		{																	\
			typedef tp_name<_Other> other;									\
		};																	\
		template<class _O>													\
		LOLIX_INLINE_CALL bool operator == (const tp_name<_O, mem_trait>& o)\
		{ return this->_alc == o._alc; }									\
		template<class _O>													\
		LOLIX_INLINE_CALL bool operator != (const tp_name<_O, mem_trait>& o)\
		{ return !(this_type::operator == (o)); }							\
																			\
		__LOLIX_ALLOC_CONSTRUCT(tp_name, void);								\
																			\
		LOLIX_INLINE_CALL	~tp_name<void, mem_trait>(void)					\
		{																	\
			_alc->release();												\
		}																	\
																			\
		template <typename _To>												\
		LOLIX_INLINE_CALL	this_type& operator = ( const tp_name<_To, mem_trait>& o)	\
		{																	\
			if ( this->_alc != o.get_allocator() )							\
			{																\
				this->_alc->release();										\
				_alc = o.get_allocator();									\
				_alc->inc_ref();											\
			}																\
																			\
			return *this;													\
		}																	\
																			\
		template <typename _To>												\
		LOLIX_INLINE_CALL	void swap(const tp_name<_To, mem_trait>& o)		\
		{																	\
			this_type tmp = o;												\
			o = *this;														\
			*this = tmp;													\
		}																	\
																			\
		::lolix::dynamic_allocator* get_allocator(void)const				\
		{ return _alc; }													\
		operator ::lolix::dynamic_allocator* (void)const					\
		{ return _alc; }													\
	private:																\
		::lolix::dynamic_allocator*	_alc;									\
	}


namespace lolix{namespace toy{
	template<typename _Ty>
	LOLIX_INLINE_CALL	void	LOLIX_DESTROY(_Ty* tp)
	{
		(tp = tp);
		tp->~_Ty();
	}
	LOLIX_INLINE_CALL	void	LOLIX_DESTROY(void* /*tp*/)
	{
	}
	template<typename _Ty>
	LOLIX_INLINE_CALL	void	LOLIX_DESTROY(_Ty* tp, size_type n)
	{
		for ( size_type i = 0; i != n; ++i )
			LOLIX_DESTROY(tp+i);
	}
	LOLIX_INLINE_CALL	void	LOLIX_DESTROY(void* /*tp*/, size_type /*n*/)
	{
	}
}}


namespace lolix{namespace toy{
	LOLIX_ALLOC("lolix::toy::allocator", allocator);
}
using toy::allocator;
}


#if			__LOLIX__TMP_DEF__NEED_POP_NEW_DEF
	#pragma pop_macro("new")
#endif	//	__LOLIX__TMP_DEF__NEED_POP_NEW_DEF
#undef		__LOLIX__TMP_DEF__NEED_POP_NEW_DEF


#endif	//	!defined(__LOLIX__TOY_ALLOCATOR__K_IN_G__)

